﻿Imports System.IO
Imports System.Net
Imports System.Net.Sockets
Imports System.Text
Imports System.Threading
Imports System.Xml

Public Class WebServer

#Region "Enum"
    
#End Region

#Region "Declarations"
    Private Shared SingleWebserver As WebServer

    Private LocalTCPListener As TcpListener
    Private _LocalPort As Integer = 305
    Private LocalAddress As IPAddress = GetIPAddress()
    Private _DefaultDocument As String = "default.htm"
    Private WebThread As Thread
    Private _VirtualRoot As String
#End Region

#Region "Events"
    Public Event OnAccessLog(ByVal Message As String)
    Public Event OnError(ByVal Message As String)
    Public Event OnWarning(ByVal Message As String)
    Public Event OnInfo(ByVal Message As String)
#End Region

#Region "Properties"
    Public Property LocalPort() As Integer
        Get
            Return _LocalPort
        End Get
        Set(ByVal Value As Integer)
            _LocalPort = Value
        End Set
    End Property

    Public Property DefaultDocument() As String
        Get
            Return _DefaultDocument
        End Get
        Set(ByVal Value As String)
            _DefaultDocument = Value
        End Set
    End Property

    Public Property VirtualRoot() As String
        Get
            Return _VirtualRoot
        End Get
        Set(ByVal Value As String)
            _VirtualRoot = Value
        End Set
    End Property
#End Region

#Region "Methods"

    Private Sub PushLog(ByVal Message As String, ByVal ClientIP As String, ByVal LogType As eLogType)
        Dim AccessPattern As String = "-{0}: {1} <{2}-{3}-{4} {5}:{6}:{7}:{8}>" 'Request, Client, Date
        Dim ErrorPattern As String = "-{0}: {1} <{2}-{3}-{4} {5}:{6}:{7}:{8}>" 'Error, Client, Date
        Dim WarningPattern As String = "-{0}: {1} <{2}-{3}-{4} {5}:{6}:{7}:{8}>" 'Message, Client, Date
        Dim InfoPattern As String = "-{0}: {1} <{2}-{3}-{4} {5}:{6}:{7}:{8}>" 'Message, Client, Date

        Dim LogMessage As String = ""

        Select Case LogType
            Case eLogType.Access
                LogMessage = String.Format(AccessPattern, Message, ClientIP, Now.Year, Now.Month, Now.Day, Now.Hour, Now.Minute, Now.Second, Now.Millisecond)
                RaiseEvent OnAccessLog(LogMessage)
            Case eLogType.Error
                LogMessage = String.Format(ErrorPattern, Message, ClientIP, Now.Year, Now.Month, Now.Day, Now.Hour, Now.Minute, Now.Second, Now.Millisecond)
                RaiseEvent OnError(LogMessage)
            Case eLogType.Warning
                LogMessage = String.Format(WarningPattern, Message, ClientIP, Now.Year, Now.Month, Now.Day, Now.Hour, Now.Minute, Now.Second, Now.Millisecond)
                RaiseEvent OnWarning(LogMessage)
            Case eLogType.Info
                LogMessage = String.Format(InfoPattern, Message, ClientIP, Now.Year, Now.Month, Now.Day, Now.Hour, Now.Minute, Now.Second, Now.Millisecond)
                RaiseEvent OnInfo(LogMessage)
        End Select
    End Sub

    Private Function GetIPAddress() As IPAddress
        Return IPAddress.Any
    End Function

    Friend Shared Function GetWebServer() As WebServer
        If SingleWebserver Is Nothing Then
            SingleWebserver = New WebServer
        End If
        Return SingleWebserver
    End Function

    Public Sub StartWebServer(ByVal Port As Integer, ByVal VirtualRoot As String)
        Try
            Me.LocalPort = Port
            Me.VirtualRoot = VirtualRoot
            LocalTCPListener = New TcpListener(LocalAddress, _LocalPort)
            LocalTCPListener.Start()
            WebThread = New Thread(AddressOf StartListen)
            WebThread.Start()
            PushLog("Server Started", "", eLogType.Info)
        Catch ex As Exception
            PushLog("Error Starting the Server: " & ex.Message, "", eLogType.Error)
        End Try
    End Sub

    Public Function GetLocalPath(ByVal sWebServerRoot As String, ByVal sDirName As String) As String
        Try
            Dim sVirtualDir As String = ""
            Dim sRealDir As String = ""
            Dim iStartPos As Integer = 0
            sDirName.Trim()
            sWebServerRoot = sWebServerRoot.ToLower
            sDirName = sDirName.ToLower
            Select Case sDirName
                Case "/"
                    sRealDir = _VirtualRoot
                Case Else
                    If Mid$(sDirName, 1, 1) = "/" Then
                        sDirName = Mid$(sDirName, 2, Len(sDirName))
                    End If
                    sRealDir = _VirtualRoot & sDirName.Replace("/", "\")
            End Select
            Return sRealDir
        Catch ex As Exception
            PushLog("Error in GetLocalPath: " & ex.Message, "", eLogType.Error)
            Return ""
        End Try
    End Function

    Private Sub New()
        'create a singleton
    End Sub

    Private Sub StartListen()
        Try

            Dim sWebserverRoot = _VirtualRoot
            Dim PhysicalFilePath As String = ""
            Dim sFormattedMessage As String = ""
            
            Do While True
                'accept new socket connection
                Dim mySocket As Socket = LocalTCPListener.AcceptSocket
                If mySocket.Connected Then
                    Dim objProcessor As New HttpProcessor(mySocket, PhysicalFilePath, DefaultDocument, _VirtualRoot)
                    Dim ThProcessor As New System.Threading.Thread(AddressOf objProcessor.Processor)
                    ThProcessor.Start()
                End If
            Loop
        Catch ex As Exception
            PushLog("Error in StartListen: " & ex.Message, "", eLogType.Error)
        End Try
    End Sub
    Public Sub StopWebServer()
        Try
            LocalTCPListener.Stop()
            WebThread.Abort()
            PushLog("Server Stopped", "", eLogType.Info)
        Catch ex As Exception
            PushLog("Error while stopping the server: " & ex.Message, "", eLogType.Error)
        End Try
    End Sub

#End Region

End Class